/*
	This file is part of PropExtractor.

	PropExtractor is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	PropExtractor is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with PropExtractor. If not, see <http://www.gnu.org/licenses/>.
*/

#include "PEIncludes.h"

#include "PEArchive.h"
#include "PETools.h"

namespace pe
{


	PE_EXPORT int PEArchiveRawOpenFile(PEStream* a_Target, PEArchiveRaw* a_Archive, PEArchiveEntryRaw* a_Entry)
	{
		PEStreamOpen(a_Target, a_Archive->path, L"rb", false);
		PEStreamSetPath(a_Target, a_Entry->path);

		// ... but with an offset

		PEStreamSetOffset(a_Target, a_Entry->offset, a_Entry->filesize);

		return PE_OK;
	}

	PE_EXPORT int PEArchiveRawGetEntry(PEArchiveEntryRaw** a_Target, PEArchiveRaw* a_Archive, unsigned int a_Index)
	{
		if (a_Index >= a_Archive->entries_total) { return -1; }

		*a_Target = &a_Archive->entries[a_Index];

		return PE_OK;
	}

	PE_EXPORT int PEArchiveRawSaveCompressedFile(PEArchiveRaw* a_Archive, PEArchiveEntryRaw* a_Entry, const wchar_t* a_WorkingDir, const char* a_Pattern)
	{
		// get data

		PEStream read;
		PEArchiveRawOpenFile(&read, a_Archive, a_Entry);

		unsigned int filesize;
		PEStreamGetFileSize(&read, &filesize);

		char* data = new char[filesize];
		PEStreamRead(&read, data, filesize, 1);

		PEStreamClose(&read);

		// get path

		wchar_t path[_MAX_PATH];
		size_t path_len;
		GetPatternedPath(path, &path_len, a_Pattern, a_Entry->path, a_WorkingDir);

		// write to file

		FILE* write_file = _wfopen(path, L"w+b");
		fwrite(data, filesize, 1, write_file);
		fclose(write_file);

		return PE_OK;
	}

	PEArchiveEntry::PEArchiveEntry()
	{
		m_LocalPath = NULL;
		m_FileSize = m_Offset = 0;
	}

	PEArchiveEntry::~PEArchiveEntry()
	{

	}

	int PEArchiveEntry::SaveCompressedToFile(const wchar_t* a_Path)
	{
		wchar_t path[_MAX_PATH];
		size_t path_length;
		GetPatternedPath(path, &path_length, "%workingdir%%dir%%name%%ext%", a_Path);

		PEStream save;
		if (PEStreamOpen(&save, path, L"wb") == -1)
		{
			return -1;
		}

		PEStream* read = GetStream();

		unsigned int datasize;
		PEStreamGetFileSize(read, &datasize);
		byte* data = new byte[datasize];
		PEStreamRead(read, data, datasize, 1);

		fwrite(data, datasize, 1, save.handle);

		PEStreamClose(&save);
		PEStreamClose(read);

		delete read;

		return PE_OK;
	}

	PEArchive::PEArchive()
	{
		m_Children = NULL;
		m_ChildrenCount = 0;

		m_SubArchives = NULL;
		m_SubArchivesCount = 0;

		m_Shared = NULL;
	}

	PEArchive::~PEArchive()
	{
		if (m_Shared)
		{
			PEStreamClose(m_Shared);
			delete m_Shared;
		}
	}

	PEArchiveEntry* PEArchive::GetEntry(unsigned int a_Index)
	{
		if (a_Index >= m_ChildrenCount) { return NULL; }
		return &m_Children[a_Index];
	}

	PEStream* PEArchive::GetEntryStream(unsigned int a_Index)
	{
		if (a_Index >= m_ChildrenCount) { return NULL; }
		PEArchiveEntry* curr = &m_Children[a_Index];

		curr->GetStreamShared(m_Shared);

		return m_Shared;
	}

	PEArchiveEntry* PEArchive::GetEntryByFileName(const wchar_t* a_Name)
	{
		if (m_ChildrenCount == 0) { return NULL; }

		for (unsigned int i = 0; i < m_ChildrenCount; i++)
		{
			if (!wcscmp(m_Children[i].GetFileName(), a_Name))
			{
				return &m_Children[i];
			}
		}

		return NULL;
	}

	int PEArchive::AddEntry(const wchar_t* a_Path, unsigned int a_Offset)
	{
		return PE_OK;
	}

	int PEArchive::SetEntries(unsigned int a_Total)
	{
		return PE_OK;
	}

	void PEArchive::SetStream(PEStream* a_Stream)
	{
		m_Stream = a_Stream;
		PEStreamGetPath(a_Stream, &m_Path);
		
		m_Shared = new PEStream;
		PEStreamOpen(m_Shared, m_Path, L"rb");
	}

}; // namespace pe